#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#pragma endregion

#include "stdafx.h"

const wchar_t* XmlDocumentPropertyName = L"Xml_Document";
const wchar_t* XmlXPathPropertyName = L"Xml_XPath";
const wchar_t* XmlResultPropertyName = L"Xml_Result";
const int MAX_XPATH_LENGTH = 1000;

HRESULT XmlSelectSingleNode(wchar_t* documentPath, wchar_t* xpath, ATL::CComBSTR& result)
{
	ATL::CComPtr<IXMLDOMDocument> xmlDocument;
	HRESULT hr = xmlDocument.CoCreateInstance(L"Microsoft.XMLDOM", NULL);
	ATLASSERT(SUCCEEDED(hr));
	if(FAILED(hr)) return hr;

	hr = xmlDocument->put_async(VARIANT_FALSE);
	ATLASSERT(SUCCEEDED(hr));
	if(FAILED(hr)) return hr;

	VARIANT_BOOL loadResult;
	hr = xmlDocument->load(ATL::CComVariant(documentPath), &loadResult);
	ATLASSERT(SUCCEEDED(hr));
	if(FAILED(hr)) return hr;
	if(loadResult == VARIANT_FALSE)
		return E_FAIL;

	ATL::CComPtr<IXMLDOMNode> xmlNode;
	hr = xmlDocument->selectSingleNode(CComBSTR(xpath), &xmlNode);
	ATLASSERT(SUCCEEDED(hr));
	if(FAILED(hr)) return hr;
	if(hr == S_FALSE) return E_FAIL;

	DOMNodeType nodeType;
	hr = xmlNode->get_nodeType(&nodeType);
	ATLASSERT(SUCCEEDED(hr));
	if(FAILED(hr)) return hr;

	if(nodeType == NODE_ELEMENT)
	{
		ATL::CComPtr<IXMLDOMElement> xmlElement;
		hr = xmlNode.QueryInterface(&xmlElement);
		ATLASSERT(SUCCEEDED(hr));
		if(FAILED(hr)) return hr;

		hr = xmlElement->get_text(&result);
		if(FAILED(hr)) return hr;
		ATLASSERT(SUCCEEDED(hr));
		return hr;
	}
	else
	{
		ATL::CComVariant nodeValue;
		hr = xmlNode->get_nodeValue(&nodeValue);
		ATLASSERT(SUCCEEDED(hr));
		if(FAILED(hr)) return hr;
		if(hr == S_FALSE) return E_FAIL;

		if(nodeValue.vt == VT_BSTR && nodeValue.bstrVal != NULL)
		{
			result = nodeValue.bstrVal;
			return hr;
		}
		return E_FAIL;
	}
}

UINT __stdcall Xml_SelectSingleNode(MSIHANDLE hInstall)
{
	UINT msiResult = ERROR_SUCCESS;
	HRESULT hr = S_OK;

	wchar_t documentPath[MAX_PATH + 1];
	DWORD documentPathLength = MAX_PATH;
	msiResult = ::MsiGetProperty(hInstall, XmlDocumentPropertyName, documentPath, &documentPathLength);
	if(msiResult != ERROR_SUCCESS) return msiResult;
	if(documentPathLength == 0) return ERROR_FUNCTION_FAILED;

	wchar_t xpath[MAX_XPATH_LENGTH + 1];
	DWORD xpathLength = MAX_XPATH_LENGTH;
	msiResult = ::MsiGetProperty(hInstall, XmlXPathPropertyName, xpath, &xpathLength);
	if(msiResult != ERROR_SUCCESS) return msiResult;
	if(xpathLength == 0) return ERROR_FUNCTION_FAILED;

	ATL::CComBSTR result;
	hr = XmlSelectSingleNode(documentPath, xpath, result);
	if(SUCCEEDED(hr))
		msiResult = ::MsiSetProperty(hInstall, XmlResultPropertyName, result.m_str);
	
	return msiResult;
}

